﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PServiceBus.Core.Interface;
using System.Collections.Concurrent;
using System.Threading;

namespace PServiceBus.Core.Manager {
    public class WebSocketConnectionManager {

        const int MIN_KEEP_ALIVE = 300000;

        static RegisteredWaitHandle _handle;
        static ManualResetEvent _reset = new ManualResetEvent(false);
        static int _keepAlive;

        static WebSocketConnectionManager() {
            if (WebSocketConnectionSetting.KeepAlive == null)
                WebSocketConnectionSetting.KeepAlive = MIN_KEEP_ALIVE;
            _keepAlive = WebSocketConnectionSetting.KeepAlive.Value;
            _keepAlive = _keepAlive <= 0 ? MIN_KEEP_ALIVE : _keepAlive;
        }


        public static void Start() {
            _handle = ThreadPool.RegisterWaitForSingleObject(_reset, ProcessEvent, null, _keepAlive, true);
        }

        public static void Stop() {
            _reset.Set();
        }

        private static void ProcessEvent(object state, bool timeout) {
            if (timeout) {
                Ping();
                _handle = ThreadPool.RegisterWaitForSingleObject(_reset, ProcessEvent, null, _keepAlive, true);
            } else {
                _handle.Unregister(null);
            }
        }

        private static readonly List<Guid> _deadList = new List<Guid>();

        private static readonly ConcurrentDictionary<Guid, IWebSocketConnection> _connections =
            new ConcurrentDictionary<Guid, IWebSocketConnection>();

        private static readonly string _kaMessage = "{\"psbka\":\"1\"}";

        public static void Register(IWebSocketConnection connection) {
            if (_connections.ContainsKey(connection.ID)) return;
            _connections.TryAdd(connection.ID, connection);
        }

        public static void UnRegister(IWebSocketConnection connection) {
            _connections.TryRemove(connection.ID, out connection);
        }

        private static void Ping() {
            
            foreach (var param in _connections) {
                var connection = param.Value;
                try {
                    connection.Send(_kaMessage);
                } catch {
                    _deadList.Add(connection.ID);
                }
            }
            if (_deadList.Any()) {
                IWebSocketConnection connection;
                foreach (var key in _deadList) 
                    _connections.TryRemove(key, out connection);
            }
            _deadList.Clear();
        }

        
    }

    public class WebSocketConnectionSetting {
        public static int? KeepAlive { get; set; }
    }
}
